// 泛型是类型变量
// 泛型是为了定义的类型能够重用（一个类型可以用于多个场景），并且可以表明多个 变量的类型 之间的 关联
function identity<Type>(arg:Type):Type {
    return arg
}
//这里用到泛型Type 把函数的参数和返回值的类型之间的关系表示清楚

// 调用泛型函数 有两种方式
    // 方式一 ：
            // 调用时，把所有类型参数 和 函数参数 都传入
         const output =   identity<string>('a')

    // 方式二 ：
            // 调用时，只传入函数的参数，ts根据 传入的参数的类型 自动 推断出 类型参数的值

    // 大多数情况下，不需要传入类型参数，ts就可以进行类型参数的推断，判断出类型参数的值，但是有些复杂的情况，无法推断，则需要显式的传递类型参数
    

// 类型参数默认可以是任何类型
function loggingIdentity<Type>(arg: Type): Type {
    // console.log(arg.length);   arg是Type类型，Type类型可以取到任何类型值，可能是没有length属性的类型，所以这里报错
//   Property 'length' does not exist on type 'Type'.
    return arg;
  }

  function loggingIdentit1<Type>(arg: Array<Type>): Array<Type> {
    console.log(arg.length); // 这里使用了length属性，说明我们知道它是一个数组或者是字符串或者数字，这里就假设我们知道参数是数组
    return arg;
  }

  // 上面是创建了一个 具体的 泛型函数，下面要创建一个 
    //   泛型函数类型
   type F = <T>(a:T)=>T // 这里给一个函数类型增加了类型参数，这样子就成了泛型函数类型
   const fun:F = loggingIdentity
    //    可以把函数写成对象的形式，在对象里面加上泛型
    type O = {
        <T>(a:T):T
    }
    const fun1 :O  = loggingIdentity  // 函数的对象类型 跟函数的函数类型 是同样的类型
    // 泛型接口，把类型参数放在接口上
    interface EX<T> { //这里就是在定义接口的时候加上泛型
        (a:T):T
    }
    // 使用类型别名 添加泛型 
    type OJ<T> = string|T[]

    class GenericNumber<NumType> {
        // 在这个字面量（类名）里面，所有的实例的属性和方法都可以使用这个类型变量，但是它静态属性（类自己的属性和方法） 不能使用这个类型变量
        zeroValue: NumType;
        add: (x: NumType, y: NumType) => NumType;
      }   // 这个语法是在创建一个js类的时候，顺便加了泛型和类型定义
    //  是不是还有专门的定义类的类型，接口是可用来定义类的
       
      let myGenericNumber = new GenericNumber<number>();
      myGenericNumber.zeroValue = 0;
      myGenericNumber.add = function (x, y) {
        return x + y;
      };

    //   ts里的继承语法:
        //   A接口 extends B接口 
        //  A接口 extends B类
        //  A类型变量 extends B接口
        //   A类型变量 extends B类
        // 使用继承语法，首先的要定义一个接口或者是类，用于继承，用来做约束
    interface Y<U> extends GenericNumber<number>{
        length:number,
        a:U[]
    }
    function loggingIdentity2<Type extends Y<number>>(arg: Type): Type {
        console.log(arg.length);
    //   Property 'length' does not exist on type 'Type'.
        return arg;
      }
    //   loggingIdentity2([])
    
    //   js中也有继承语法，是类的继承
    class b {
        c:1
    }
    class a extends b {
        d:2
    }